home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / chpasswd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-26  |  5.0 KB  |  225 lines

  1. /*
  2.  * Copyright 1990, 1991, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Permission is granted to copy and create derivative works for any
  6.  * non-commercial purpose, provided this copyright notice is preserved
  7.  * in all copies of source code, or included in human readable form
  8.  * and conspicuously displayed on all copies of object code or
  9.  * distribution media.
  10.  *
  11.  * chpasswd - update passwords in batch
  12.  *
  13.  *    chpasswd reads standard input for a list of colon separated
  14.  *    user names and new passwords.  the appropriate password
  15.  *    files are updated to reflect the changes.  because the
  16.  *    changes are made in a batch fashion, the user must run
  17.  *    the mkpasswd command after this command terminates since
  18.  *    no password updates occur until the very end.
  19.  */
  20.  
  21. #include <stdio.h>
  22. #include "pwd.h"
  23. #include <fcntl.h>
  24. #include <string.h>
  25. #include "config.h"
  26. #ifdef    SHADOWPWD
  27. #include "shadow.h"
  28. #endif
  29.  
  30. #ifndef    lint
  31. static    char    sccsid[] = "@(#)chpasswd.c    3.4    08:57:30    6/10/91";
  32. #endif
  33.  
  34. char    *Prog;
  35.  
  36. extern    char    *pw_encrypt();
  37. extern    char    *l64a();
  38.  
  39. /* 
  40.  * If it weren't for the different structures and differences in how
  41.  * certain fields were manipulated, I could just use macros to replace
  42.  * the function calls for the different file formats.  So I make the
  43.  * best of things and just use macros to replace a few of the calls.
  44.  */
  45.  
  46. #ifdef    SHADOWPWD
  47. #define    pw_lock        spw_lock
  48. #define    pw_open        spw_open
  49. #define    pw_close    spw_close
  50. #define    pw_unlock    spw_unlock
  51. #endif
  52.  
  53. /*
  54.  * usage - display usage message and exit
  55.  */
  56.  
  57. usage ()
  58. {
  59.     fprintf (stderr, "usage: %s\n", Prog);
  60.     exit (1);
  61. }
  62.  
  63. main (argc, argv)
  64. int    argc;
  65. char    **argv;
  66. {
  67.     char    buf[BUFSIZ];
  68.     char    *name;
  69.     char    *newpwd;
  70.     char    *cp;
  71. #ifdef    SHADOWPWD
  72.     struct    spwd    *sp;
  73.     struct    spwd    newsp;
  74.     struct    spwd    *spw_locate();
  75. #else
  76.     struct    passwd    *pw;
  77.     struct    passwd    newpw;
  78.     struct    passwd    *pw_locate();
  79.     char    newage[5];
  80. #endif
  81.     int    errors = 0;
  82.     int    line = 0;
  83.     long    now = time ((long *) 0) / (24L*3600L);
  84.  
  85.     if (Prog = strrchr (argv[0], '/'))
  86.         Prog++;
  87.     else
  88.         Prog = argv[0];
  89.  
  90.     if (argc != 1)
  91.         usage ();
  92.  
  93.     /*
  94.      * Lock the password file and open it for reading.  This will
  95.      * bring all of the entries into memory where they may be
  96.      * updated.
  97.      */
  98.  
  99.     if (! pw_lock ()) {
  100.         fprintf (stderr, "%s: can't lock password file\n", Prog);
  101.         exit (1);
  102.     }
  103.     if (! pw_open (O_RDWR)) {
  104.         fprintf (stderr, "%s: can't open password file\n", Prog);
  105.         exit (1);
  106.     }
  107.  
  108.     /*
  109.      * Read each line, separating the user name from the password.
  110.      * The password entry for each user will be looked up in the
  111.      * appropriate file (shadow or passwd) and the password changed.
  112.      * For shadow files the last change date is set directly, for
  113.      * passwd files the last change date is set in the age only if
  114.      * aging information is present.
  115.      */
  116.  
  117.     while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
  118.         line++;
  119.         if (cp = strrchr (buf, '\n')) {
  120.             *cp = '\0';
  121.         } else {
  122.             fprintf (stderr, "%s: line %d: line too long\n",
  123.                 Prog, line);
  124.             errors++;
  125.             continue;
  126.         }
  127.  
  128.         /*
  129.          * The username is the first field.  It is separated
  130.          * from the password with a ":" character which is
  131.          * replaced with a NUL to give the new password.  The
  132.          * new password will then be encrypted in the normal
  133.          * fashion with a new salt generated.
  134.          */
  135.  
  136.         name = buf;
  137.         if (cp = strchr (name, ':')) {
  138.             *cp++ = '\0';
  139.         } else {
  140.             fprintf (stderr, "%s: line %d: missing new password\n",
  141.                 Prog, line);
  142.             errors++;
  143.             continue;
  144.         }
  145.         newpwd = cp;
  146.         cp = pw_encrypt (newpwd, (char *) 0);
  147.  
  148.         /*
  149.          * Get the password file entry for this user.  The user
  150.          * must already exist.
  151.          */
  152.  
  153. #ifdef    SHADOWPWD
  154.         if (! (sp = spw_locate (name)))
  155. #else
  156.         if (! (pw = pw_locate (name)))
  157. #endif
  158.         {
  159.             fprintf (stderr, "%s: line %d: unknown user %s\n",
  160.                 Prog, line, name);
  161.             errors++;
  162.             continue;
  163.         }
  164.  
  165.         /*
  166.          * The freshly encrypted new password is merged into
  167.          * the user's password file entry and the last password
  168.          * change date is set to the current date.
  169.          */
  170.  
  171. #ifdef    SHADOWPWD
  172.         newsp = *sp;
  173.         newsp.sp_pwdp = cp;
  174.         newsp.sp_lstchg = now;
  175. #else
  176.         newpw = *pw;
  177.         newpw.pw_passwd = cp;
  178. #ifdef    ATT_AGE
  179.         if (newpw.pw_age[0]) {
  180.             strcpy (newage, newpw.pw_age);
  181.             strcpy (newage + 2, l64a (now / 7));
  182.             newpw.pw_age = newage;
  183.         }
  184. #endif
  185. #endif
  186.  
  187.         /* 
  188.          * The updated password file entry is then put back
  189.          * and will be written to the password file later, after
  190.          * all the other entries have been updated as well.
  191.          */
  192.  
  193. #ifdef    SHADOWPWD
  194.         if (! spw_update (&newsp))
  195. #else
  196.         if (! pw_update (&newpw))
  197. #endif
  198.         {
  199.             fprintf (stderr, "%s: line %d: cannot update password entry\n",
  200.                 Prog, line);
  201.             errors++;
  202.             continue;
  203.         }
  204.     }
  205.  
  206.     /*
  207.      * Any detected errors will cause the entire set of changes
  208.      * to be aborted.  Unlocking the password file will cause
  209.      * all of the changes to be ignored.  Otherwise the file is
  210.      * closed, causing the changes to be written out all at
  211.      * once, and then unlocked afterwards.
  212.      */
  213.  
  214.     if (errors) {
  215.         fprintf (stderr, "%s: error detected, changes ignored\n", Prog);
  216.         pw_unlock ();
  217.         exit (1);
  218.     }
  219.     if (! pw_close ()) {
  220.         fprintf (stderr, "%s: error updating password file\n", Prog);
  221.         exit (1);
  222.     }
  223.     (void) pw_unlock ();
  224. }
  225.